import random
from threading import   Thread


from django.conf import settings

from django.http import HttpResponse
from django.shortcuts import render
import pickle,base64
# Create your views here.
from django_redis import get_redis_connection
from rest_framework import response
from rest_framework.response import Response
from itsdangerous import TimedJSONWebSignatureSerializer as TJS
from rest_framework.views import APIView
from rest_framework.generics import CreateAPIView, RetrieveAPIView, UpdateAPIView
from rest_framework_jwt.views import ObtainJSONWebToken

from celery_tasks.sms.tasks import send_sms_code
from meiduo_mall.utils.captcha.captcha import captcha
from users.setializers import UserSerializer, UserDetailSerializer, UserUpdateSerializer
from rest_framework.permissions import IsAuthenticated
# 获取前段发送的短信验证码,RetriveAPIView 但是需要自己重写发送短信验证码的功能
# 用基本类,没有分页,过滤使用APIView


# from libs.yuntongxun.sms import CCP

# 4.2
# def send_sms_code(mobile,sms_code):
#     """
#     发送短信
#     :param mobile:
#     :param sms_code:
#     :return:
#     """
#     ccp = CCP()
#     ccp.send_template_sms(mobile,[sms_code,5],1)
from users.models import User
from users.utils import merge_cart_cookie_to_redis


class SMS_CODEView(APIView):
    """
    短信验证码
    1.获取前端发送的手机号
    2.随机生成短信验证码
    3.将数据保存到缓存中
    3.调用云通讯发送短信验证码
    4.返回结果
    """

    def get(self,request,mobile):
        # 1.建立连接redis 的对象秒内
        # 判断前端发送短信的时间是60
        coon = get_redis_connection("sms_code")
        flag = coon.get("sms_code_flag_%s"%mobile)
        if flag:
            return Response({"errno":"请求过于频繁"})
        # 2.生成短信验证码
        sms_code = "%06d" %random.randint(0,999999)
        print(sms_code)

        # 需要连接两次redis数据库,增加服务器压力
        # # 3.保存短信验证码到缓存中
        # coon.setex("sms_code_%s"% mobile,300,sms_code)
        # # 任意设置一个值,让他60秒内有效
        # coon.setex("sms_code_flag_%s"%mobile,60,1)

        # 使用管道来进行连接
        # 3.1生成管道对象
        pl= coon.pipeline()
        # 3.2使用管道对象
        pl.setex("sms_code_%s"%mobile,300,sms_code)
        pl.setex("sms_code_flag_%s"%mobile,60,1)
        # 连接缓存,传入写入指令
        pl.execute()

        # 发送短信网络请求阻塞,使用多线程

        # # 4.1发送短信
        # ccp = CCP()
        # ccp.send_template_sms(mobile,[sms_code,5],1)

        # 4.2创建线程进行发送短信
        # t = Thread(target=send_sms_code,kwargs={"mobile":"mobile","sms_code":"sms_code"})
        # t.start()
        # t.join()

        # 4.3 使用celery 异步发送短信

        send_sms_code.delay(mobile,sms_code)

        # 5.结果返回
        return Response({"message":"ok"})


# 用户名重复判断
class UserNameView(APIView):
    # 获取前端数据,进行正则匹配数据
    def get(self,request,username):
        # 根据有户名查询数据
        count = User.objects.filter(username=username).count()
        return Response({
            "count":count
        })


# 手机号重复判断
class MobileView(APIView):
    """
    手机号重复判断
    """
    def get(self,request,mobile):
        count =User.objects.filter(mobile =mobile).count()
        return Response({
            "count":count
        })


class UsersView(CreateAPIView):
    """
    用户注册
    """
    serializer_class = UserSerializer


class UserDetailView(RetrieveAPIView):
    """
    返回用户信息
    """

    serializer_class = UserDetailSerializer
    permission_classes = [IsAuthenticated]
    # get_object 需要pk值，但是前端没有传递id 所以需要重写get_object

    def get_object(self):
        print(self.request.user)
        # 因为RetriveAPIView 继承了APIView APIVIEW 中写了self.request = request
        return self.request.user

class UserUpdateView(UpdateAPIView):
    """
    更新邮箱
    """
    serializer_class = UserUpdateSerializer

    def get_object(self):
        return self.request.user


class EmailVerify(APIView):
    """
    邮箱验证
    # 获取前端数据
    # 验证数据
    # 查询用户
    # 将用户的email_active 改为true
    """
    def get(self,request):
        # print(request.method)
        # 获取前端数据
        token = request.query_params.get("token")
        # 验证数据,解密成功，则验证成功
        tjs = TJS(settings.SECRET_KEY,60*60)
        try:
            data = tjs.loads(token)
            print(data)
        except:
            return Response({"errors":"无效的token数据"},status=400)

        # 查询用户，更新用户的email_active
        username = data.get("name")
        try:
            user = User.objects.get(username=username)
        except:
            return Response({"errors":"查询不到用户"},status =400)
        user.email_active = True
        user.save()

        # 返回结果
        return Response({"message":"ok"})


class UserLoginView(ObtainJSONWebToken):
    """
    合并购物车
    """
    def post(self, request, *args, **kwargs):
        response = super().post(request, *args, **kwargs)
        # 合并购物车
        # 获取cookie
        serializer = self.get_serializer(data=request.data)

        if serializer.is_valid():
            user = serializer.object.get('user') or request.user
            response = merge_cart_cookie_to_redis(request, user, response)
        return response


# class UpdatePasswordView(APIView):
#
#     def put(self, request, pk):
#
#         data = request.data
#         user = User.objects.get(id=pk)
#
#         if not user.check_password(data['old_password']):
#             raise Exception('原密码输入错误')
#
#         if data['password'] != data['password2']:
#             raise Exception('两次密码输入不一致')
#
#         user.set_password(data['password'])
#         user.save()
#         return Response({'message':'OK'})





# 忘记密码
class ImageCode(APIView):
    # 生成图片验证码
    def get(self, request, uuid):
        # 检查参数是传入,如果没传，直接return
        if not uuid:
            return Response({'errors': '无uuid值'}, status=400)
        # 调用captcha工具包,来生成图片验证码
        name, text, image = captcha.generate_captcha()
        # 在redis中存储图片验证码内容（text）
        conn = get_redis_connection('image_code')
        # string类型写入redis
        conn.setex('image_code_%s'%uuid, 300, text)
        # 返回前端图片，使用make_response(image)
        return HttpResponse(image, content_type='image.jpg')


class UsernameCode(APIView):
    # 输入用户名
    def get(self, request, username):
        # 1、获取前端数据
        # token = request.query_params.get('token')
        image_code = request.query_params.get('text')
        uuid = request.query_params.get('image_code_id')
        # print(image_code)
        # print(uuid)
        # print(username)
        try:
            user = User.objects.get(username=username)
        except:
            return Response({'errors': '用户不存在'}, status=404)
        mobile = user.mobile
        # 从redis中获取数据
        conn = get_redis_connection('image_code')
        real_image_code = conn.get('image_code_%s'%uuid).decode()
        # print(real_image_code)
        if not image_code.lower() == real_image_code.lower():
            return Response({'errors': '验证码错误'}, status=400)
        tjs = TJS(settings.SECRET_KEY, 300)
        access_token = tjs.dumps({'mobile': mobile}).decode()
        # 5、返回结果
        return Response({'mobile': mobile,
                         'access_token': access_token})


class FindPassword_SendSMSCODE(APIView):
    def get(self, request):
        access_token = request.query_params.get('access_token')
        tjs = TJS(settings.SECRET_KEY, 300)
        data = tjs.loads(access_token)
        mobile = data.get('mobile')
        # print(mobile)
        # 1.建立redis链接对象
        conn = get_redis_connection('sms_codes')
        flag = conn.get('sms_code_flag_%s' % mobile)
        if flag:
            return Response({'error': '请求过于频繁'}, status=400)
        # 2.生成短信验证码
        sms_code = '%06d' % random.randint(0, 999999)
        print(sms_code)
        # 3.保存验证码到缓存中
        # 建立链接redis对象
        conn = get_redis_connection('sms_codes')
        # 管道用法
        pl = conn.pipeline()
        pl.setex('sms_code_%s' % mobile, 300, sms_code)
        pl.setex('sms_code_flag_%s' % mobile, 60, 1)
        # 连接redis缓存，传入写入指令
        pl.execute()
        # 使用celery发送短信
        send_sms_code.delay(mobile, sms_code)
        return Response({'mobile': mobile})



class FindPassword_SMSCODE(APIView):
    def get(self, request, username):
        user = User.objects.get(username=username)
        mobile = user.mobile
        user_id = user.id
        sms_code = request.query_params.get('sms_code')
        # 从redis中获取数据
        conn = get_redis_connection('sms_codes')
        real_sms_code = conn.get('sms_code_%s' % mobile).decode()
        # print(real_image_code)
        if not sms_code == real_sms_code:
            return Response({'errors': '验证码错误'}, status=400)
        tjs = TJS(settings.SECRET_KEY, 300)
        access_token = tjs.dumps({'mobile': mobile}).decode()
        return Response({'user_id': user_id,
                         'access_token': access_token})


class FindPassword_NewPassword(APIView):
    def post(self, request, user_id):
        data = request.data
        password = data['password']
        password2 = data['password2']
        if not password == password2:
            return Response({'errors': '密码不一致'}, status=400)
        user = User.objects.get(id=user_id)
        user.set_password(password)
        user.save()
        return Response({'message': True})


    def put(self, request, user_id):

        data = request.data
        user = User.objects.get(id=user_id)

        if not user.check_password(data['old_password']):
            raise Exception('原密码输入错误')

        if data['password'] != data['password2']:
            raise Exception('两次密码输入不一致')

        user.set_password(data['password'])
        user.save()
        return Response({"message":"ok"})



